题目
题目描述
有些邪恶富人们喜欢玩生死游戏。简单的说就是找一些穷人,让他们进行相互厮杀。富人们则在旁观看并下注。
今天的游戏跟以往有些不同。参与游戏的穷人排成了一个n*m的矩阵,你的任务是组织游戏并决定这些人的生死。
如果第i行,第j列的人幸存了下来,你将获得Wij块钱,否则你将得到Bij块钱。
同时,富人们会提出一些奇怪的要求。他们每个人都会指定一个子矩阵,然后说:如果这个子矩阵的所有穷人都死了(或者都幸存下来了),你将得到S块钱。
你并不关心这些穷人的生死,你只希望你得到的钱尽可能多。
请注意,这里对杀人没有限制,你可以杀掉所有人,也可以一个也不杀。
输入
第一行,三个空格间隔的整数n,m,r ,分别表示矩阵的行数、列数和富人们提出的要求的数量。
接下来是n*m个整数,表示矩阵B。
接下来是n*m个整数,表示矩阵W。(0<=Bij,Wij<=100)
接下来r行,每行描述一个要求:
每个要求有6个空格间隔的整数构成:R1,C1,R2,C2,T,S。它表示一个子矩阵的左上角(R1,C1)和右下角(R2,C2)的坐标。T=1表示矩阵中的所有人必须死,T=0表示矩阵中所有人都必须活下来。S表示如果你满足了这个要求,你将得到的钱数。(0<=S<=10000)请注意,这里对杀人没有限制,你可以杀掉所有人,也可以一个也不杀。
输出
一行,一个整数,表示所求答案。
样例1
输入
2 2 3
34 44
63 30
1 9
53 57
1 2 2 2 1 2843
1 1 2 1 0 2169
2 1 2 1 1 6980
输出
9994
样例2
输入
2 2 3
50 93
65 70
52 28
91 25
1 1 2 1 0 9862
2 1 2 1 1 1876
2 2 2 2 0 4190
输出
14313
提示
对于30%的数据 1<=n,m<=10 0<=r=1000
对于50%的数据 1<=n,m<=30 0<=r<=10000
对于100%的数据 1<=n,m<=50 0<=r<=50000
分析
这道题的选择之间有关系,很容易想到最小割。
我们从S到每个点连容量为
bi
的边,从每个点到T连容量为
wi
的边,当点在S时,就代表这个人死了,在T则活着。
然后考虑富人的要求,对于每个要求我们新增一个点。
对于第
i
个要求:
- 如果要求所有人都活着,那么当这个点在S时,就会付出
si 的代价。就从这个点到T连一条容量为 si 的边,再从矩阵内所有的点向这个点连一条容量为 +∞ 的边。如果要求所有人都死,那么当这个点在T时,就会付出 si 的代价。就从S到这个点连一条容量为 si 的边,再从这个点到矩阵内所有的点连一条容量为 +∞ 的边。
显然边十分多,但是连接的点往往是在一个二维区间内的所有点,可以效仿A+B Problem,用二维线段树优化这道题。
这道题,其实就是 (A+B)2Problem 。
代码
#include<cstdio> #include<cstring> #include<queue> #include<algorithm> #define MAXN 50 #define MAXR 50000 #define INF 0x7fffffff using namespace std; queue<int>q; struct node{ int v,cap; node *back,*next; }*adj[MAXN*MAXN*20+MAXR+10],edge[10000000+10],*ecnt=edge; int root[MAXN*4+10],ls[MAXN*MAXN*4*4+10],rs[MAXN*MAXN*4*4+10],tot,m,S,T,n,r,ans,c,dist[MAXN*MAXN*20+MAXR+10],vd[MAXN*MAXN*20+MAXR+10],flow,id[MAXN*MAXN*4*4+10][2],tcnt; void addedge(int u,int v,int cap){ node *p=++ecnt; p->v=v; p->cap=cap; p->next=adj[u]; adj[u]=p; p=p->back=++ecnt; p->v=u; p->cap=0; p->next=adj[v]; adj[v]=p; p->back=ecnt-1; } void build2(int &i,int l,int r,int ll,int rr){ i=++tcnt; id[i][0]=++tot,id[i][1]=++tot; if(l==r){ for(int j=ll;j<=rr;j++){ addedge(id[i][1],(j-1)*m+l,INF); addedge((j-1)*m+l,id[i][0],INF); } return; } int mid=(l+r)>>1; build2(ls[i],l,mid,ll,rr); build2(rs[i],mid+1,r,ll,rr); addedge(id[i][1],id[ls[i]][1],INF); addedge(id[i][1],id[rs[i]][1],INF); addedge(id[ls[i]][0],id[i][0],INF); addedge(id[rs[i]][0],id[i][0],INF); } void build1(int i,int l,int r){ build2(root[i],1,m,l,r); if(l==r) return; int mid=(l+r)>>1; build1(i<<1,l,mid); build1((i<<1)|1,mid+1,r); } void link2(int i,int l,int r,int ll,int rr,bool f,int c){ if(ll<=l&&rr>=r){ if(f) addedge(tot,id[i][1],c); else addedge(id[i][0],tot,c); return; } if(l>rr||r<ll) return; int mid=(l+r)>>1; link2(ls[i],l,mid,ll,rr,f,c); link2(rs[i],mid+1,r,ll,rr,f,c); } void link1(int i,int l,int r,int ll,int rr,int wl,int wr,bool f,int c){ if(ll<=l&&rr>=r){ link2(root[i],1,m,wl,wr,f,c); return; } if(l>rr||r<ll) return; int mid=(l+r)>>1; link1(i<<1,l,mid,ll,rr,wl,wr,f,c); link1((i<<1)|1,mid+1,r,ll,rr,wl,wr,f,c); } void Read(int &x){ char c; while(c=getchar(),c!=EOF) if(c>='0'&&c<='9'){ x=c-'0'; while(c=getchar(),c>='0'&&c<='9') x=x*10+c-'0'; ungetc(c,stdin); return; } } void read(){ Read(n),Read(m),Read(r); int i,j,b,w; S=n*m+1,tot=T=S+1; build1(1,1,n); for(i=1;i<=n;i++) for(j=1;j<=m;j++){ Read(b); addedge(S,(i-1)*m+j,b); ans+=b; } for(i=1;i<=n;i++) for(j=1;j<=m;j++){ Read(w); addedge((i-1)*m+j,T,w); ans+=w; } int h1,h2,s1,s2,t,s; for(i=1;i<=r;i++){ Read(h1),Read(s1),Read(h2),Read(s2),Read(t),Read(s); ans+=s; if(t){ addedge(S,++tot,s); link1(1,1,n,h1,h2,s1,s2,1,s); } else{ addedge(++tot,T,s); link1(1,1,n,h1,h2,s1,s2,0,s); } } } void bfs(){ q.push(T); int u; while(!q.empty()){ u=q.front(); q.pop(); for(node *p=adj[u];p;p=p->next){ if(p->back->cap&&!dist[p->v]){ dist[p->v]=dist[u]+1; q.push(p->v); } } } dist[T]=0; } int dfs(int u,int augu){ if(u==T) return augu; int augv=0,v,delta,mind=tot-1; for(node *p=adj[u];p;p=p->next) if(p->cap){ v=p->v; if(dist[u]==dist[v]+1){ delta=min(augu-augv,p->cap); delta=dfs(v,delta); augv+=delta; p->cap-=delta; p->back->cap+=delta; if(augu==augv||dist[S]>=tot) return augv; } mind=min(dist[v],mind); } if(!augv){ if(!--vd[dist[u]]) dist[S]=tot; vd[dist[u]=mind+1]++; } return augv; } void sap(){ bfs(); for(int i=1;i<=tot;i++){ if(!dist[i]){ dist[i]=tot; continue; } vd[dist[i]]++; } dist[T]=0,vd[0]++; while(dist[S]<tot) flow+=dfs(S,INF); } int main() { read(); sap(); printf("%d\n",ans-flow); }